using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;

using Deepcode.Flux.Core.Data;
using Deepcode.Flux.Core.Systems.Workflow.Info;
using Deepcode.Flux.Core.Systems.Workflow.Enums;

namespace Deepcode.Flux.Core.Systems.Workflow.Bases
{
	/// <summary>
	/// Represents a tasking record
	/// </summary>
	public class Tasking
	{
		// Private fields for storing record fields //
		private int					_PK_ID = -1;
		private int					_FK_ProcessID = -1;
		private string				_TaskCaption = "";
		private string				_CSV_OperatorID = "";
		private string				_CSV_GroupID = "";
		private string				_GetUserMethod = "";
		private bool				_SystemTask = false;
		private int					_SystemExitAt = 0;
		private WorkflowTimescale	_SystemExitAtUnit = WorkflowTimescale.MINUTE;
		private int					_ActivateTaskAt = 0;
		private WorkflowTimescale	_ActivateTaskAtUnit = WorkflowTimescale.MINUTE;
		private int					_DeadlineTaskAt = 0;
		private WorkflowTimescale	_DeadlineTaskAtUnit = WorkflowTimescale.MINUTE;


		// Public fields exposing record fields //
		public int PK_ID { get { return _PK_ID; } set { _PK_ID = value; } }
		public int FK_ProcessID { get { return _FK_ProcessID; } set { _FK_ProcessID = value; } }
		public string TaskCaption{ get{ return _TaskCaption; } set{ _TaskCaption = value; }}
		public string CSV_OperatorID { get{ return _CSV_OperatorID; } set { _CSV_OperatorID = value; }}
		public string CSV_GroupID { get{ return _CSV_GroupID; } set { _CSV_GroupID = value; }}
		public string GetUserMethod { get{ return _GetUserMethod; } set { _GetUserMethod = value; }}
		public bool SystemTask { get{ return _SystemTask; } set { _SystemTask = value; }}
		public int SystemExitAt { get{ return _SystemExitAt; } set { _SystemExitAt = value; }}
		public WorkflowTimescale SystemExitAtUnit { get{ return _SystemExitAtUnit; } set { _SystemExitAtUnit = value; }}
		public int ActivateTaskAt { get{ return _ActivateTaskAt; } set { _ActivateTaskAt = value; }}
		public WorkflowTimescale ActivateTaskAtUnit { get{ return _ActivateTaskAtUnit; } set { _ActivateTaskAtUnit = value; }}
		public int DeadlineTaskAt { get{ return _DeadlineTaskAt; } set { _DeadlineTaskAt = value; }}
		public WorkflowTimescale DeadlineTaskAtUnit { get{ return _DeadlineTaskAtUnit; } set { _DeadlineTaskAtUnit = value; }}

		// Linkback's
		public Process ParentProcess { get { return new Processes().GetProcessByID(this.FK_ProcessID); } }
		public TaskExitPath[] ExitPaths { get { return new TaskExitPaths().GetExitPathsForTaskingID(this.PK_ID); } }

		// Constructor to create new without loading
		public Tasking() { }

		// Constructor loading from a data row
		public Tasking(DataRow InitFromRow)
		{
			_PK_ID = SQLUtility.DBNull(InitFromRow["PK_ID"], -1);
			_FK_ProcessID = SQLUtility.DBNull(InitFromRow["FK_ProcessID"], -1);
			_TaskCaption = SQLUtility.DBNull(InitFromRow["TaskCaption"], "");
			_CSV_OperatorID = SQLUtility.DBNull(InitFromRow["CSV_OperatorID"], "");
			_CSV_GroupID = SQLUtility.DBNull(InitFromRow["CSV_GroupID"], "");
			_GetUserMethod = SQLUtility.DBNull(InitFromRow["GetUserMethod"], "");
			_SystemTask = SQLUtility.DBNull(InitFromRow["SystemTask"], false);
			_SystemExitAt = SQLUtility.DBNull(InitFromRow["SystemExitAt"], -1);
			_SystemExitAtUnit = (WorkflowTimescale) SQLUtility.DBNull(InitFromRow["SystemExitAtUnit"], -1);
			_ActivateTaskAt = SQLUtility.DBNull(InitFromRow["ActivateTaskAt"], -1);
			_ActivateTaskAtUnit = (WorkflowTimescale) SQLUtility.DBNull(InitFromRow["ActivateTaskAtUnit"], -1);
			_DeadlineTaskAt = SQLUtility.DBNull(InitFromRow["DeadlineTaskAt"], -1);
			_DeadlineTaskAtUnit = (WorkflowTimescale) SQLUtility.DBNull(InitFromRow["DeadlineTaskAtUnit"], -1);
		}

		#region Special properties for grid binding
		/// <summary>
		/// Returns text representing who this tasking applies to.
		/// </summary>
		public string CalcFor
		{
			get
			{
				if (this.SystemTask) return "System";
				string result = "";
				if ((this.CSV_GroupID != "") || (this.CSV_OperatorID != "") || (this.GetUserMethod != ""))
				{
					// Get a workflow engine
					WorkflowEngine engine = new WorkflowEngine(this.ParentProcess.ParentDefinition.HandlerCodeID);
					GetOperatorNames(ref result, engine);
					GetGroupNames(ref result, engine);
					GetMethodName(ref result, engine);
				}
				if (result == "") return "No-one";
				return result;
			}
		}
		/// <summary>
		/// Asks the engine to provide the operator names for this tasking
		/// </summary>
		/// <param name="target"></param>
		/// <param name="engine"></param>
		private void GetOperatorNames(ref string target, WorkflowEngine engine)
		{
			if (this.CSV_OperatorID == "") return;

			string[] IDList = this.CSV_OperatorID.Split(',');
			foreach (string StrID in IDList)
			{
				int ID = -1;
				try { ID = Int32.Parse(StrID); }
				catch { ID = -1; }

				if (ID != -1)
				{
					WorkflowTaskableOperator op = engine.GetTaskableOperator( ID );
					if (op != null)
					{
						if (target != "") target += ", ";
						target += op.OperatorName;
					}
				}
			}
		}
		/// <summary>
		/// Asks the engine to provide the names of the groups for this tasking
		/// </summary>
		/// <param name="target"></param>
		/// <param name="engine"></param>
		private void GetGroupNames(ref string target, WorkflowEngine engine)
		{
			if (this.CSV_GroupID == "") return;

			string[] IDList = this.CSV_GroupID.Split(',');
			foreach (string StrID in IDList)
			{
				int ID = -1;
				try { ID = Int32.Parse(StrID); }
				catch { ID = -1; }

				if (ID != -1)
				{
					WorkflowTaskableGroup grp = engine.GetTaskableGroup(ID);
					if (grp != null)
					{
						if (target != "") target += ", ";
						target += grp.GroupName;
					}
				}
			}
		}
		/// <summary>
		/// Asks the engine to provide the name of the taskable method
		/// </summary>
		/// <param name="target"></param>
		/// <param name="engine"></param>
		private void GetMethodName(ref string target, WorkflowEngine engine)
		{
			if (this.GetUserMethod == "") return;

			WorkflowTaskableMethodInfo inf = engine.GetWorkflowTaskableMethodInfo(this.GetUserMethod);
			if (inf != null)
			{
				if (target != "") target += ", ";
				target += inf.FriendlyName;
			}
		}
		/// <summary>
		/// Returns text representing when this tasking either
		/// activates, or (for system tasks), when the task will
		/// be automatically executed.
		/// </summary>
		public string CalcStart
		{
			get
			{
				if (this.SystemTask)
					return String.Format("{0} {1}", this.SystemExitAt, WorkflowTimescaleUtils.GetTimescaleName((WorkflowTimescale)this.SystemExitAtUnit));
				else
					return String.Format("{0} {1}", this.ActivateTaskAt, WorkflowTimescaleUtils.GetTimescaleName((WorkflowTimescale)this.ActivateTaskAtUnit));
			}
		}
		/// <summary>
		/// Returns text representing the deadline for this tasking.
		/// If the deadline is > 100years, it's assumed there is 
		/// no deadline
		/// </summary>
		public string CalcDeadline
		{
			get
			{
				// System tasks have no deadline
				if (this.SystemTask) return "No deadline";
				// Deadlines of 100 years+ are same as no deadline
				if ((((WorkflowTimescale)this.DeadlineTaskAtUnit) == WorkflowTimescale.YEAR) && (this.DeadlineTaskAt >= 100)) return "No deadline";

				return String.Format("{0} {1}", this.DeadlineTaskAt, WorkflowTimescaleUtils.GetTimescaleName((WorkflowTimescale)this.DeadlineTaskAtUnit));
			}
		}
		#endregion

		/// <summary>
		/// For system taskings this creates the one and only
		/// system exit path record for actions to be associated 
		/// with it.
		/// </summary>
		public void CreateSystemExitPath()
		{
			if( this.PK_ID == -1 ) throw new Exception("Cannot create a system exit path on an unsaved tasking");

			TaskExitPaths exits = new TaskExitPaths();
			TaskExitPath exit = new TaskExitPath();
			exit.FK_TaskingID = this.PK_ID;
			exit.Caption = "System Exit Path";
			exit.uiTaskMethod = "";
			exit.CSV_AllowedGroups = "";
			exits.Save( exit );
		}

	}
}
